import { isEqual } from 'lodash-es'
import type {
  FormItem,
  configType,
  FormItemRule,
  formApi,
} from '../types/index.ts'


import { isVueComponent, isVueComponentOrVNode } from './isVueComponent'

export function useDependencies(
  item: Ref<FormItem>,
  data: Record<string, any> = {},
  otherData: Record<string, any> = {}
) {
  const ifData = ref<boolean>(true)
  const showData = ref<boolean>(true)
  const disabledData = ref<boolean>(false)
  const rulesData = ref<FormItemRule[] | FormItemRule | null>(null)
  const configPropsData = otherData.configProps ?? ref<configType | null>(null)
  const renderExample = ref<Component | null>(null)
  const { dependencies } = item.value
  const { allData, component, coreValue } = otherData

  let obj = ref<Readonly<formApi>>({} as any)
  
  if (item.value.dependencies) {
    watch(
      () => {
        const arr = item.value.dependencies?.triggerFields?.map(
          (field: string) => {
            if (data.value) return data.value[field]
            return []
          }
        )
        return arr
      },
      (newValue, oldValue) => {
        // 使用lodash的isEqual来判断数组是否相等
        if (isEqual(newValue, oldValue)) return
        nextTick(() => {
          obj.value = readonly({
            ...otherData,
            isEvent: readonly(otherData.isEvent),
            allEvent: readonly(allData.allEvent),
            allFormItemCoreRefs: readonly(allData.allRefs),
            allFormItemRefs: readonly(allData.allFormItemRefs),
            formItemRef: computed(() => {
              return allData?.allFormItemRefs?.[item.value.field]
            }),
            formItemCoreRef: computed(() => {
              return allData?.allRefs?.[item.value.field]
            }),
            tableInfo: readonly(allData.tableInfo ?? {}),
            propKey: readonly(otherData.propKey ?? []),
            changeData: allData.allChangeData[item.value.field],
            itemAt: item as any,
            rowData: readonly(data),
            triggerFields: (item.value.dependencies?.triggerFields?.map(
              (field) => {
                return ({
                  isEditByRow: otherData.isEditByRow.value ?? true,
                  isEvent: allData.allEvent?.[field] ?? false,
                  ...allData.allChangeData[field]
                })
              }
            ) || []) as any,
          })
          const readonlyData = readonly(data.value ?? {})
          dependencies?.trigger?.(readonlyData, obj.value)
          if (dependencies?.if) {
            // 判断是否是promise如果是的话就使用then接收。如果不是的话就直接赋值
            const resValue = dependencies?.if?.(readonlyData, obj.value)
            if (isPromise(resValue)) {
              resValue.then((res) => {
                if(typeof res !== 'symbol') ifData.value = res as any
              })
            } else {
              if(typeof resValue !== 'symbol') ifData.value = resValue  as any
            }
          }
          if (dependencies?.show) {
            // 判断是否是promise如果是的话就使用then接收。如果不是的话就直接赋值
            const resValue = dependencies?.show?.(readonlyData, obj.value)
            if (isPromise(resValue)) {
              resValue.then((res) => {
                if(typeof res !== 'symbol') showData.value = res as any
              })
            } else {
              if(typeof resValue !== 'symbol') showData.value = resValue as any
            }
          }
          if (dependencies?.disabled) {
            // 判断是否是promise如果是的话就使用then接收。如果不是的话就直接赋值
            const resValue = dependencies?.disabled?.(readonlyData, obj.value)
            if (isPromise(resValue)) {
              resValue.then((res) => {
                if(typeof res !== 'symbol') disabledData.value = res as any
              })
            } else {
              if(typeof resValue !== 'symbol') disabledData.value = resValue as any
            }
          }
          if (dependencies?.rules) {
            // 判断是否是promise如果是的话就使用then接收。如果不是的话就直接赋值
            const resValue = dependencies?.rules?.(readonlyData, obj.value)
            if (isPromise(resValue)) {
              resValue.then((res) => {
                if(typeof res !== 'symbol') rulesData.value = res as any
              })
            } else {
              if(typeof resValue !== 'symbol') rulesData.value = resValue as any
            }
          }
          if (dependencies?.configProps) {
            // 判断是否是promise如果是的话就使用then接收。如果不是的话就直接赋值
            const resValue = dependencies?.configProps?.(readonlyData, obj.value)
            if (isPromise(resValue)) {
              resValue.then((res) => {
                if(typeof res !== 'symbol') configPropsData.value = res
              })
            } else {
              if(typeof resValue !== 'symbol') configPropsData.value = resValue
            }
          }
          if (dependencies?.value) {
            // 判断是否是promise如果是的话就使用then接收。如果不是的话就直接赋值
            const resValue = dependencies?.value?.(readonlyData, obj.value)
            if (isPromise(resValue)) {
              resValue.then((res) => {
                if(typeof res !== 'symbol') coreValue.value = res
              })
            } else {
              if(typeof resValue !== 'symbol') coreValue.value = resValue
            }
          }
          const componentScoped = readonly(component)
          watchEffect(() => {
            if (dependencies?.render) {
              const formData = readonly(data.value ?? {})
              const renderReturn = dependencies?.render?.(formData, {...obj.value, formData: data.value, component: componentScoped})
              if(isVueComponentOrVNode(toValue(renderReturn))) {
                renderExample.value = h(toValue(renderReturn))
                return
              }
              renderExample.value = h('span', {
                innerHTML: typeof renderReturn === 'string' ? renderReturn : JSON.stringify(renderReturn)
              })
            }
          })
          
        })
      },
      {
        immediate: item.value.dependencies?.immediate ?? true,
      }
    )
  }

  return {
    ifData,
    showData,
    disabledData,
    rulesData,
    configPropsData,
    renderExample,
    otherData: obj
  }
}

export { isVueComponent, isVueComponentOrVNode }
export { getOptions, useHandleChangeData } from './changeData'


function isPromise(value: unknown): value is Promise<unknown> {
  return (
    typeof value === 'object' &&
    value !== null &&
    'then' in value &&
    'catch' in value &&
    typeof value.then === 'function' &&
    typeof value.catch === 'function'
  );
}
